﻿using Basic.FlowModel;
using Basic.FlowModel.DB;
using Basic.FlowModel.Flow;
using Basic.FlowModel.Node;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Flow.Model;
using SqlSugar;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;
using WeDonekRpc.Helper.IdGenerator;
using WeDonekRpc.Model;
using WeDonekRpc.SqlSugar;

namespace Basic.FlowDAL.lmpl
{
    internal class FlowListDAL : BasicDAL<DBFlowList, long>, IFlowListDAL
    {
        public FlowListDAL ( IRepository<DBFlowList> basicDAL ) : base(basicDAL, "info")
        {
        }
        public long Add ( FlowAdd add )
        {
            DBFlowList data = add.ConvertMap<FlowAdd, DBFlowList>();
            data.CreateTime = DateTime.Now;
            data.Id = IdentityHelper.CreateId();
            data.VerNum = ConstDic.FlowInitVer;
            data.Status = FlowStatus.起草;
            DBFlowNode node = new DBFlowNode
            {
                AuditType = FlowAuditType.无,
                FlowId = data.Id,
                Id = IdentityHelper.CreateId(),
                NodeName = "开始",
                NodeLvl = 1,
                NodeCode = "001",
                NodeType = FlowNodeType.开始节点,
                IsAllowEdit = true,
                IsAllowCancel = false,
                OpinionMust = false,
                MinAuditPass = 0
            };
            ISqlQueue<DBFlowList> queue = this._BasicDAL.BeginQueue();
            queue.Insert(data);
            queue.InsertBy(node);
            _ = queue.Submit();
            return data.Id;
        }

        public void Enable ( DBFlowList flow, NodeSet[] sets )
        {
            ISqlQueue<DBFlowList> queue = this._BasicDAL.BeginQueue();
            queue.UpdateOneColumn(a => a.Status == FlowStatus.启用, a => a.Id == flow.Id);
            sets.ForEach(a =>
            {
                queue.UpdateBy<DBFlowNode>(new DBFlowNode
                {
                    Id = a.Id,
                    NodeLvl = a.NodeLvl,
                    RootNodeId = a.RootId
                }, "NodeLvl", "RootNodeId");
            });
            _ = queue.Submit();
        }
        public Result[] GetChildren<Result> ( long sourceId ) where Result : class, new()
        {
            ISugarQueryable<Result>[] tables = new ISugarQueryable<Result>[] {
                this._BasicDAL.Queryable.Where(a=>a.Id==sourceId).Take(1).Select<Result>(),
                this._BasicDAL.Queryable.Where(a=>a.SourceId==sourceId).Select<Result>(),
            };
            return this._BasicDAL.Gets<Result>(tables);
        }

        public string GetMaxVer ( long id )
        {
            return this._BasicDAL.Get(a => a.SourceId == id, a => a.VerNum, a => new
            {
                len = SqlFunc.Desc(SqlFunc.Length(a.VerNum)),
                a.VerNum
            }, OrderByType.Desc);
        }

        public Result[] Query<Result> ( FlowQueryParam query, IBasicPage paging, out int count ) where Result : class
        {
            paging.InitOrderBy("Id", true);
            return this._BasicDAL.Query<Result>(query.ToWhere(), paging, out count);
        }

        public long Save ( FlowBodyAdd add )
        {
            DBFlowList data = new DBFlowList
            {
                CreateBy = add.CreateBy,
                DefFormId = add.DefFormId,
                CreateTime = DateTime.Now,
                FlowName = add.FlowName,
                FlowType = add.FlowType,
                Id = IdentityHelper.CreateId(),
                Remark = add.Remark,
                SourceId = add.SourceId,
                Status = FlowStatus.起草,
                VerNum = add.VerNum
            };
            Dictionary<long, long> nodeId = new Dictionary<long, long>();
            List<DBFlowNodeAuditEmp> auditEmps = new List<DBFlowNodeAuditEmp>();
            List<DBFlowNodeEvent> evs = new List<DBFlowNodeEvent>();
            List<DBFlowNodeMsg> msgs = new List<DBFlowNodeMsg>();
            List<DBFlowNodeFormPower> powers = new List<DBFlowNodeFormPower>();
            List<DBFlowFormDataRelation> relations = new List<DBFlowFormDataRelation>();
            DBFlowNode[] nodes = add.Nodes.ConvertMap<NodeAdd, DBFlowNode>(( a, b ) =>
            {
                b.Id = IdentityHelper.CreateId();
                nodeId.Add(a.Id, b.Id);
                b.FlowId = data.Id;
                if ( a.AuditEmp != null )
                {
                    DBFlowNodeAuditEmp db = a.AuditEmp.ConvertMap<NodeAuditEmpAdd, DBFlowNodeAuditEmp>();
                    db.Id = IdentityHelper.CreateId();
                    db.FlowId = data.Id;
                    db.NodeId = b.Id;
                    auditEmps.Add(db);
                }
                if ( !a.NodeEvent.IsNull() )
                {
                    DBFlowNodeEvent[] ev = a.NodeEvent.ConvertMap<NodeEventAdd, DBFlowNodeEvent>();
                    ev.ForEach(c =>
                    {
                        c.Id = IdentityHelper.CreateId();
                        c.FlowId = data.Id;
                        c.NodeId = b.Id;
                        evs.Add(c);
                    });
                }
                if ( !a.Msgs.IsNull() )
                {
                    DBFlowNodeMsg[] ev = a.Msgs.ConvertMap<NodeMsgAdd, DBFlowNodeMsg>();
                    ev.ForEach(c =>
                    {
                        c.Id = IdentityHelper.CreateId();
                        c.FlowId = data.Id;
                        c.NodeId = b.Id;
                        msgs.Add(c);
                    });
                }
                if ( !a.FormPowers.IsNull() )
                {
                    DBFlowNodeFormPower[] power = a.FormPowers.ConvertMap<NodeFormPower, DBFlowNodeFormPower>();
                    power.ForEach(c =>
                    {
                        c.Id = IdentityHelper.CreateId();
                        c.FlowId = data.Id;
                        c.NodeId = b.Id;
                        powers.Add(c);
                    });
                }
                if ( !a.Relation.IsNull() )
                {
                    DBFlowFormDataRelation[] list = a.Relation.ConvertMap<DataRelationAdd, DBFlowFormDataRelation>();
                    list.ForEach(c =>
                    {
                        c.Id = IdentityHelper.CreateId();
                        c.FlowId = data.Id;
                        c.NodeId = b.Id;
                        relations.Add(c);
                    });
                }
                return b;
            });
            nodes.ForEach(c =>
            {
                if ( c.BackNodeId.HasValue )
                {
                    c.BackNodeId = nodeId[c.BackNodeId.Value];
                }
                if ( c.IntoWaitNodeId.HasValue )
                {
                    c.IntoWaitNodeId = nodeId[c.IntoWaitNodeId.Value];
                }
                if ( c.OutWaitNodeId.HasValue )
                {
                    c.OutWaitNodeId = nodeId[c.OutWaitNodeId.Value];
                }
                if ( !c.IntoFormula.IsNull() )
                {
                    c.IntoFormula.ForEach(a =>
                    {
                        a.NodeId = nodeId[a.NodeId];
                    });
                }

            });
            auditEmps.ForEach(c =>
            {
                if ( c.FromNodeId.HasValue )
                {
                    c.FromNodeId = nodeId[c.FromNodeId.Value];
                }
            });
            msgs.ForEach(c =>
            {
                if ( !c.ToNodeId.IsNull() )
                {
                    c.ToNodeId = c.ToNodeId.ConvertAll(a => nodeId[a]);
                }
            });
            List<DBFlowNodeRoute> routes = new List<DBFlowNodeRoute>();
            add.Nodes.ForEach(c =>
            {
                if ( !c.ToNodeId.IsNull() )
                {
                    c.ToNodeId.ForEach(a =>
                    {
                        routes.Add(new DBFlowNodeRoute
                        {
                            Id = IdentityHelper.CreateId(),
                            FlowId = data.Id,
                            NodeId = nodeId[c.Id],
                            ToNodeId = nodeId[a],
                        });
                    });
                }
            });
            ISqlQueue<DBFlowList> queue = this._BasicDAL.BeginQueue();
            queue.Insert(data);
            queue.InsertBy(nodes);
            queue.InsertBy(auditEmps);
            queue.InsertBy(routes);
            if ( evs.Count > 0 )
            {
                queue.InsertBy(evs);
            }
            if ( msgs.Count > 0 )
            {
                queue.InsertBy(msgs);
            }
            if ( powers.Count > 0 )
            {
                queue.InsertBy(powers);
            }
            if ( relations.Count > 0 )
            {
                queue.InsertBy(relations);
            }
            _ = queue.Submit();
            return data.Id;
        }

        public void SetStatus ( DBFlowList flow, FlowStatus status )
        {
            if ( !this._BasicDAL.Update(a => a.Status == status, a => a.Id == flow.Id) )
            {
                throw new ErrorException("flow.info.status.set.fail");
            }
        }
    }
}
